package com.frame.auth.business;

import com.frame.auth.business.model.User;
import com.frame.auth.business.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 用户登录认证信息查询
 * 通过跟踪代码运行，我们发现像默认使用的 DaoAuthenticationProvider，在认证的使用都是通过一个叫 UserDetailsService 的来获取用户认证所需信息的。
 * AbstractUserDetailsAuthenticationProvider 定义了在 authenticate 方法中通过 retrieveUser 方法获取用户信息，
 * 子类 DaoAuthenticationProvider 通过 UserDetailsService 来进行获取，
 * 一般情况，这个UserDetailsService需要我们自定义，实现从用户服务获取用户和权限信息封装到 UserDetails 的实现类。
 *
 * 一般而言，定制 UserDetailsService 就可以满足大部分需求了，在 UserDetailsService 满足不了我们的需求的时候考虑定制 AuthenticationProvider。
 * 如果直接定制UserDetailsService ，而不自定义 AuthenticationProvider，可以直接在配置文件 SecurityConfig 中这样配置。
 * @Override
 * public void configure(AuthenticationManagerBuilder auth) throws Exception {
 *     // 指定自定义的获取信息获取服务
 *     auth.userDetailsService(userDetailsService)
 * }
 *
 * @author Louis
 * @date Jun 29, 2019
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("该用户不存在");
        }
        // 用户权限列表，根据用户拥有的权限标识与如 @PreAuthorize("hasAuthority('sys:menu:view')") 标注的接口对比，决定是否可以调用接口
        Set<String> permissions = userService.findPermissions(username);
        List<GrantedAuthority> grantedAuthorities = permissions.stream().map(GrantedAuthorityImpl::new).collect(Collectors.toList());
        return new JwtUserDetails(username, user.getPassword(), grantedAuthorities);
    }
}